package characteristic

import (
	"reflect"
	"adai.design/homemaster/container/characteristic/to"
	"fmt"
	"github.com/gorilla/websocket"
)

// 用户监听或者服务器监听回调函数类型
type ConnChangeFunc func(conn *websocket.Conn, c *Characteristic, newValue, oldValue interface{})

// 设备属性发生变化回调用于执行相应的动作
type ChangeFunc func(c *Characteristic, newValue, oldValue interface{})

type Characteristic struct {
	Id 			int			`json:"cid"`
	Type 		string			`json:"type"`
	Value 		interface{}		`json:"value,omitempty"`

	Format 		string			`json:"format"`
	Unit 		string			`json:"unit,omitempty"`

	MaxValue	interface{}		`json:"max,omitempty"`
	MinValue	interface{}		`json:"min,omitempty"`
	StepValue	interface{}		`json:"step,omitempty"`

	connValueUpdateFuncs []ConnChangeFunc
	valueChangeFuncs	 []ChangeFunc
}

func NewCharacteristic(typ string) *Characteristic {
	return &Characteristic{
		Type: typ,
	}
}

// 防止越界
func (c *Characteristic) boundFloat32Value(value float32) interface{} {
	min, minOk := c.MinValue.(float32)
	max, maxOk := c.MaxValue.(float32)
	if maxOk && value > max {
		value = max
	} else if minOk && value < min {
		value = min
	}
	return value
}

// 防止越界
func (c *Characteristic) boundIntValue(value int) interface{} {
	min, minOk := c.MinValue.(int)
	max, maxOk := c.MaxValue.(int)
	if maxOk == true && value > max {
		value = max
	} else if minOk == true && value < min {
		value = min
	}
	return value
}

func (c *Characteristic) onValueUpdateFromConn(funcs []ConnChangeFunc, conn *websocket.Conn, newValue, oldValue interface{}) {
	for _, fn := range funcs {
		fn(conn, c, newValue, oldValue)
	}
}

func (c *Characteristic) onValueUpdate(funcs []ChangeFunc, newValue, oldValue interface{}) {
	for _, fn := range funcs {
		fn(c, newValue, oldValue)
	}
}

func (c *Characteristic) OnValueUpdate(fn ChangeFunc) {
	exist := false
	for _, v := range c.valueChangeFuncs {
		if fmt.Sprintf("%v", v) == fmt.Sprintf("%v", fn) {
			exist = true
			break
		}
	}

	if !exist {
		c.valueChangeFuncs = append(c.valueChangeFuncs, fn)
	}
}

func (c *Characteristic) OnValueUpdateFromConn(fn ConnChangeFunc) {
	exist := false
	for _, v := range c.connValueUpdateFuncs {
		if fmt.Sprintf("%v", v) == fmt.Sprintf("%v", fn) {
			exist = true
			break
		}
	}
	if !exist {
		c.connValueUpdateFuncs = append(c.connValueUpdateFuncs, fn)
	}
}

// conn=nil 属性发生变化
// conn!=nil 属性写入1
func (c *Characteristic) updateValue(value interface{}, conn *websocket.Conn) {
	if c.Value != nil {
		if converted, err := to.Convert(value, reflect.TypeOf(c.Value).Kind()); err == nil {
			value = converted
		}
	}

	switch c.Format {
	case FormatFloat:
		value = c.boundFloat32Value(value.(float32))
	case FormatUInt8, FormatUInt16, FormatUInt32, FormatInt32:
		value = c.boundIntValue(int(to.Int64(value)))
	}

	old := c.Value

	if conn == nil && old == value {
		return
	}

	if conn == nil {
		c.Value = value
	}

	if conn != nil {	// 网络过来的控制数据
		c.onValueUpdateFromConn(c.connValueUpdateFuncs, conn, value, old)
	} else {
		c.onValueUpdate(c.valueChangeFuncs, value, old)
	}
}

func (c *Characteristic) UpdateValue(value interface{}) {
	c.updateValue(value, nil)
}

func (c *Characteristic) UpdateValueFromConnection(value interface{}, conn *websocket.Conn) {
	c.updateValue(value, conn)
}